<?php

namespace platform\controllers;

use common\models\Circuit;
use common\models\CircuitAddress;
use common\models\LogHelper;
use common\models\Order;
use common\models\PointTime;
use common\models\Site;
use common\models\User;
use common\models\UserBalance;
use common\models\UserRebate;
use platform\core\BaseController;
use cm;
use platform\interfaces\RebateInterface;
use platform\models\SysModel;
use Yii;
use yii\db\Expression;
use yii\helpers\Json;
use yii\helpers\Url;

class RebateController extends BaseController implements RebateInterface
{
    /**
     * 列表
     * @return mixed
     */
   public function actionIndex()
    {
        $is_export=Yii::$app->request->get('is_export');
        if(Yii::$app->request->isPost||$is_export){
            $params=array_merge(Yii::$app->request->post(),Yii::$app->request->get());
            $query=UserRebate::find()
                ->with(['order'=>function($q){
                    $q->select(['id','user_id','order_number','addtime','pay_time','order_price','shift_id','circuit_id','s_id','e_id']);
                }]);
            if(!empty($params['uid']))$query->andWhere(['uid'=>$params['uid']]);
            if(!empty($params['type']))$query->andWhere(['type'=>$params['type']]);
            if(!empty($params['created_at'])){
                $created_at=explode(' 至 ',$params['created_at']);
                $query->andWhere(['between','created_at',strtotime($created_at[0]),strtotime($created_at[1])]);
            }
            if(!empty($params['status']))$query->andWhere(['status'=>$params['status']]);
            if(!empty($params['key'])){
                $order_ids=Order::find()->alias('o')
                    ->leftJoin(['u'=>User::tableName()],['u.id'=>new Expression('o.user_id')])
                    ->andWhere(['like','o.order_number',$params['key']])
                    ->orWhere(['like','u.nickname',$params['key']])
                    ->column();
                $uids=User::find()->andWhere(['like','nickname',$params['key']])->column();
                if(!count($order_ids))$order_ids=[0];
                if(!count($uids))$uids=[0];
                $query->andWhere(['or',['order_id'=>$order_ids],['uid'=>$uids]]);
            }
            if(!$is_export)$data['count']=$query->count();
            $size = empty($params['size'])?10:$params['size'];
            $page=empty($params['page'])?1:$params['page'];
            if(!$is_export)$query->limit($size)->offset(($page - 1) * $size);
            $data['data']=$query->asArray()->all();
            $order=array_column($data['data'],'order');
            $circuit_id=array_column($order,'circuit_id');
            $s_id=array_column($order,'s_id');
//            $e_id=array_column($order,'e_id');
            $circuit=[];
            if(count($circuit_id)){
                $circuit=Circuit::find()->andWhere(['id'=>$circuit_id])
                    ->select(['name','e_address','id'])
                    ->indexBy('id')->asArray()->all();
            }
            $get_on=[];
            if(count($s_id)){
                $get_on=CircuitAddress::find()
                    ->andWhere(['id'=>$s_id])
                    ->select(['address','id'])
                    ->indexBy('id')->column();
            }
            /*$debus=[];
            if(count($e_id)){
                $debus=CircuitAddress::find()->alias('ca')
                    ->leftJoin(['sca'=>Site::tableName()],['sca.id'=>new Expression('ca.site_id')])
                    ->andWhere(['ca.id'=>$e_id])
                    ->select(['sca.name as address','ca.id'])
                    ->indexBy('id')->column();
            }*/
            $uid=array_column($data['data'],'uid');
            $user=User::find()->andWhere(['id'=>$uid])->select(['nickname'])->indexBy('id')->column();

            $order_user=[];
            $user_id=array_column($order,'user_id');
            if(count($user_id)){
                $order_user=User::find()->andWhere(['id'=>$user_id])->select(['nickname'])->indexBy('id')->column();
            }
            if($is_export){
                $objPHPExcel = Cm::$libs->PHPExcel();
                $objPHPExcel->getProperties()
                    ->setTitle('Office 2007 XLSX Test Document')
                    ->setSubject('Office 2007 XLSX Test Document')
                    ->setDescription('Test document for Office 2007 XLSX, generated using PHP classes.')
                    ->setKeywords('office 2007 openxml php')
                    ->setCategory('Test result file');
                $objPHPExcel->getActiveSheet()->setTitle('订单信息');
                $objPHPExcel->getActiveSheet()
                    ->setCellValue('A1', '用户')
                    ->setCellValue('B1', '类型')
                    ->setCellValue('C1', '订单号')
                    ->setCellValue('D1', '下单人')
                    ->setCellValue('E1', '下单时间')
                    ->setCellValue('F1', '支付时间')
                    ->setCellValue('G1', '订单金额')
                    ->setCellValue('H1', '线路')
                    ->setCellValue('I1', '上下车')
                    ->setCellValue('J1', '金额')
                    ->setCellValue('K1', '操作后金额')
                    ->setCellValue('L1', '到账状态')
                    ->setCellValue('M1', '创建时间');

                $objPHPExcel->getActiveSheet()->getColumnDimension('A')->setWidth(30);
                $objPHPExcel->getActiveSheet()->getColumnDimension('B')->setWidth(15);
                $objPHPExcel->getActiveSheet()->getColumnDimension('C')->setWidth(30);
                $objPHPExcel->getActiveSheet()->getColumnDimension('D')->setWidth(30);
                $objPHPExcel->getActiveSheet()->getColumnDimension('E')->setWidth(30);
                $objPHPExcel->getActiveSheet()->getColumnDimension('F')->setWidth(30);
                $objPHPExcel->getActiveSheet()->getColumnDimension('G')->setWidth(15);
                $objPHPExcel->getActiveSheet()->getColumnDimension('H')->setWidth(30);
                $objPHPExcel->getActiveSheet()->getColumnDimension('I')->setWidth(30);
                $objPHPExcel->getActiveSheet()->getColumnDimension('J')->setWidth(15);
                $objPHPExcel->getActiveSheet()->getColumnDimension('K')->setWidth(15);
                $objPHPExcel->getActiveSheet()->getColumnDimension('L')->setWidth(15);
                $objPHPExcel->getActiveSheet()->getColumnDimension('M')->setWidth(30);
                $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel2007');
            }
            $i=2;
            foreach ($data['data'] as &$item){
                $item['order_number']='--';
                if(!$is_export&&!empty($item['order'])){
                    $item['order_number']='单号：'.$item['order']['order_number']
                        .'<br>下单人 ID:'.$item['order']['user_id'].' 昵称：'.($order_user[$item['order']['user_id']]??'')
                    .'<br>下单时间：'.$item['order']['addtime']
                    .'<br>支付时间：'.$item['order']['pay_time']
                    .'<br>订单金额：'.$item['order']['order_price']
                    .'<br>线路：'.(!empty($circuit[$item['order']['circuit_id']])?$circuit[$item['order']['circuit_id']]['name']:'')
                    .'<br>上下车：'.($get_on[$item['order']['s_id']]??'').'->'.
                        (!empty($circuit[$item['order']['circuit_id']])?$circuit[$item['order']['circuit_id']]['e_address']:'');
                }
                $item['created_at']=date('Y-m-d H:i:s',$item['created_at']);
                if($is_export){
                    $objPHPExcel->getActiveSheet()->getStyle('A' . $i)->getAlignment()
                        ->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER)->setWrapText(true);
                    $objPHPExcel->getActiveSheet()->getStyle('D' . $i)->getAlignment()
                        ->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER)->setWrapText(true);
                    $objPHPExcel->getActiveSheet()
                        ->setCellValue('A' . $i, $item['uid'].PHP_EOL.($user[$item['uid']]??''))
                        ->setCellValue('B' . $i, $item['type']==UserRebate::TYPE_GET?'佣金':'提现')
                        ->setCellValue('C' . $i, $item['order']['order_number']??'')
                        ->setCellValue('D' . $i, $item['order']['user_id'].PHP_EOL.($order_user[$item['order']['user_id']]??''))
                        ->setCellValue('E' . $i, $item['order']['addtime'])
                        ->setCellValue('F' . $i, $item['order']['pay_time'])
                        ->setCellValue('G' . $i, $item['order']['order_price'])
                        ->setCellValue('H' . $i, (!empty($circuit[$item['order']['circuit_id']])?$circuit[$item['order']['circuit_id']]['name']:''))
                        ->setCellValue('I' . $i, ($get_on[$item['order']['s_id']]??'').'->'.
                            (!empty($circuit[$item['order']['circuit_id']])?$circuit[$item['order']['circuit_id']]['e_address']:''))
                        ->setCellValue('J' . $i, $item['money'])
                        ->setCellValue('K' . $i, $item['after_money'])
                        ->setCellValue('L' . $i, UserRebate::getStatus()[$item['status']])
                        ->setCellValue('M' . $i, $item['created_at']);
                }
                $item['user']='ID：'.$item['uid'].'<br>昵称：'.($user[$item['uid']]??'');
                $i++;
            }
            if($is_export){
                $objPHPExcel->getDefaultStyle()->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
                $objPHPExcel->getActiveSheet()->getStyle('D')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
                $objPHPExcel->getActiveSheet()->getStyle('E')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
                $objPHPExcel->getActiveSheet()->getStyle('G')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_LEFT);
                $objPHPExcel->getActiveSheet()->getStyle('D1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
                $objPHPExcel->getActiveSheet()->getStyle('E1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
                $objPHPExcel->getActiveSheet()->getStyle('G1')->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::HORIZONTAL_CENTER);
                $objPHPExcel->getDefaultStyle()->getAlignment()->setHorizontal(\PHPExcel_Style_Alignment::VERTICAL_CENTER);

                $filename = date("Y年m月d日 H:i",time()).'的佣金信息';

                header('Content-Type: application/vnd.ms-excel');
                header('Content-Disposition: attachment;filename="' . $filename . '.xlsx"');
                header('Cache-Control: max-age=0');
                $objWriter->save('php://output');
                exit;
            }
            Cm::$res->paging($data);
        }
        $data['map'] = [];
        $data['map'][] = ['title' => "佣金与余额", 'url' => Url::to(['rebate/index'])];
        $data['baseUrl'] = Url::to(['rebate/index']);
        return Cm::$res->render($this, "index", $data, '佣金与余额');
    }

    /**
     * 提现审核
     */
   public function actionAudit(){
       $transaction=Yii::$app->db->beginTransaction();
       try {
           if(Cm::$redis->Exists('is_err'))throw new \Exception(Cm::$redis->get('is_err'));
           $params=Yii::$app->request->post();
           if(empty($params['id'])||empty($params['status']))throw new \Exception('参数错误');
           $rebate=UserRebate::find()->andWhere(['id' => $params['id'],'type'=>UserRebate::TYPE_DRAW])->one();
           if(!$rebate)throw new \Exception('数据无效');

           switch ($params['status']){
               case UserRebate::STATUS_PASS:
                   //打款对接
                   $openid=User::findOne($rebate->uid)->openid;
                   if(empty($openid))throw new \Exception('用户未绑定微信');
                   $trade_no='ZZ' . date("YmdHis") . rand(100000, 999999);//商家批次单号
                   $out_detail_no='DK' . date("YmdHis") . rand(100000, 999999).$rebate->uid;//商家明细单号
                   $data=[
                       [
                           'out_detail_no' => $out_detail_no,
                           'transfer_amount' => (int)bcmul($rebate->money, 100, 0),
                           'transfer_remark' => '用户提现',
                           'openid' => $openid,
                       ]
                   ];
                   [$request_data,$result_data]=$this->transfer($openid,$trade_no, $data);
                   $rebate->status=UserRebate::STATUS_PASS;
                   $rebate->request_data=Json::encode($request_data,JSON_UNESCAPED_UNICODE);
                   $rebate->result_data=Json::encode($result_data,JSON_UNESCAPED_UNICODE);
                   if(!empty($result_data['batch_id'])){
                       $rebate->status=UserRebate::STATUS_DONE;
                   }
                   $rebate->save();
                   break;
               case UserRebate::STATUS_DONE:
                   $rebate->status=UserRebate::STATUS_DONE;
                   if(!$rebate->save())throw new \Exception('操作失败');
                   break;
               case UserRebate::STATUS_REFUSE:
                   $rebate->status=UserRebate::STATUS_REFUSE;
                   if(!$rebate->save())throw new \Exception('操作失败');
                   UserBalance::addBalance($rebate->uid,$rebate->money);
                   break;
               default:
                   throw new \Exception('参数错误');
           }
           $transaction->commit();
           Cm::$res->susess([], '操作成功');
       }catch (\Exception $e){
           $transaction->rollBack();
           Cm::$res->error($e->getMessage());
       }
   }

    /**
     * @param $openid
     * @param $trade_no 转账批次单号
     * @param $money
     * @param string $desc
     * @return mixed
     */
    public function transfer($trade_no, $data, $desc='用户提现')
    {
        $money=array_column($data,'transfer_amount');
        $money = (int)(array_sum($money));
        $config = Yii::$app->params['wechat']['open'];
        $post_data = [
            "appid" => $config['appid'],//appid
            "out_batch_no" => $trade_no,//商家批次单号
            "batch_name" => $desc,//批次名称
            "batch_remark" => $desc,//批次备注
            "total_amount" => $money,// 转账金额单位为“分”
            "total_num" => count($data), // 转账总笔数
            //此处可以多笔提现  组合二维数组放到transfer_detail_list即可
            "transfer_detail_list" => $data
        ];
        $url = 'https://api.mch.weixin.qq.com/v3/transfer/batches';
        //JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE  防止中文被转义
        $result = $this->wx_post($url, json_encode($post_data, JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE));
        $result = json_decode($result, true);
        return [$result,$post_data];
    }

    /**post请求
     * @param $url
     * @param $param
     * @return bool|string
     */
    private function wx_post($url, $param)
    {
        $authorization = $this->getV3Sign($url, "POST", $param);
        $curl = curl_init();
        $headers = [
            'Authorization:' . $authorization,
            'Accept:application/json',
            'Content-Type:application/json;charset=utf-8',
            'User-Agent:Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36',
        ];
        curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($curl, CURLOPT_TIMEOUT, 500);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($curl, CURLOPT_URL, $url);
        curl_setopt($curl, CURLOPT_POSTFIELDS, $param);
        curl_setopt($curl, CURLOPT_POST, true);
        $res = curl_exec($curl);
        curl_close($curl);
        return $res;
    }

    /**
     * 微信提现V3签名
     * @param $url
     * @param $http_method
     * @param $body
     * @return string
     */
    private function getV3Sign($url, $http_method, $body)
    {
        $nonce = strtoupper($this->createNonceStr(32));
        $timestamp = time();
        $url_parts = parse_url($url);
        $canonical_url = ($url_parts['path'] . (!empty($url_parts['query']) ? "?${url_parts['query']}" : ""));
        $cert_dir = ROOT_PATH.DS."config".DS."payment_cert".DS."wechatpay".DS;
        $sslKeyPath = $cert_dir."apiclient_key.pem";
        //拼接参数
        $message = $http_method . "\n" .
            $canonical_url . "\n" .
            $timestamp . "\n" .
            $nonce . "\n" .
            $body . "\n";
        $private_key = $this->getPrivateKey($sslKeyPath);
        openssl_sign($message, $raw_sign, $private_key, 'sha256WithRSAEncryption');
        $sign   = base64_encode($raw_sign);
        $token = sprintf('WECHATPAY2-SHA256-RSA2048 mchid="%s",nonce_str="%s",timestamp="%s",serial_no="%s",signature="%s"', $this->mchid, $nonce, $timestamp, $this->serial_no, $sign);
        return $token;
    }


    /*每天1.30定时执行佣金到账*/
    public function actionRebate()
    {
        LogHelper::Logging(Yii::getAlias("@common/runtime/" . date("Ymd") . ".txt"), Json::encode([date('Y-m-d H:i:s',time())]));
        echo date('Y-m-d H:i:s',time()).PHP_EOL;
        set_time_limit(0);
        ini_set('memory_limit', '2048M');
        $new_time=time();
        //佣金到账中且该订单 车次 已过发车时间
        $query=UserRebate::find()->alias('ur')
            ->leftJoin(['o'=>Order::tableName()],['o.id'=>new Expression('ur.order_id')])
            ->leftJoin(['p'=>PointTime::tableName()],['o.p_id'=>new Expression('p.id')])
            ->andWhere(['ur.type'=>UserRebate::TYPE_GET,'ur.status'=>UserRebate::STATUS_PASS,'o.rebate_issue'=>Order::REBATE_ISSUE_NO])
            ->andWhere(['o.order_status'=>[Order::STATUS_TO_PAID_DELIVERED,Order::STATUS_PAID_DELIVERED,Order::STATUS_DEPART,Order::STATUS_COMPLETED]])
            ->andWhere(['<=','p.departuretime',date('Y-m-d H:i:s',$new_time)])
            ->select(['ur.id','o.rebate_price','o.bind_uid','ur.order_id']);
        $size = 100;
        $page=1;
        $total=0;
        while(true){
            $offset = ($page - 1) * $size;
            echo $offset . PHP_EOL;
            $data = (clone $query)->limit($size)->offset($offset)->asArray()->all();
            if (empty($data)) {
                break;
            }
            $transaction=Yii::$app->db->beginTransaction();
            try {
                $ur_ids=array_column($data,'id');
                $res = UserRebate::updateAll(['status' => UserRebate::STATUS_DONE, 'updated_at' => $new_time], [
                    'and',
                    ['status' => UserRebate::STATUS_PASS],
                    ['type' => UserRebate::TYPE_GET],
                    ['in', 'id', $ur_ids]
                ]);
                $total+=$res;
                if ($res==count($ur_ids)){
                    foreach ($data as $datum){
                        $order=Order::findOne($datum['order_id']);
                        if($order->rebate_issue){
                            LogHelper::Logging(Yii::getAlias("@common/runtime/order佣金到账失败" . date("Ymd") . ".txt"), Json::encode(['记录ID'=>$datum['order_id']]));
                            continue;
                        }
                        $order->rebate_issue=Order::REBATE_ISSUE;
                        if(!$order->save()){
                            LogHelper::Logging(Yii::getAlias("@common/runtime/order佣金到账失败" . date("Ymd") . ".txt"), Json::encode(['记录ID'=>$datum['order_id'],'error'=>current($order->getFirstErrors())]));
                            continue;
                        }
                        UserBalance::addBalance($datum['bind_uid'],$datum['rebate_price']);
                    }
                }
                $transaction->commit();
            }catch (\Exception $e){
                $transaction->rollBack();
                LogHelper::Logging(Yii::getAlias("@common/runtime/佣金到账失败" . date("Ymd") . ".txt"), Json::encode(['记录ID'=>$ur_ids,$e->getMessage().'-'.$e->getLine()]));
                $total-=$res;
                continue;
            }
            $page++;
        }
        LogHelper::Logging(Yii::getAlias("@common/runtime/佣金到账成功" . date("Ymd") . ".txt"), Json::encode(['执行完毕 条数:'.$total]));
        echo '执行完毕 条数:'.$total.PHP_EOL;
    }

    public function actionRebates(){
        $data=Order::find()->andWhere([
            'rebate_status'=>Order::REBATE_STATUS_YES,
            'order_status'=>[Order::STATUS_TO_PAID_DELIVERED,Order::STATUS_PAID_DELIVERED,Order::STATUS_DEPART,Order::STATUS_COMPLETED]
        ])->andWhere(['>','rebate_price',0])->select(['id','bind_uid','rebate_price','pay_time'])
        ->asArray()->all();
        foreach ($data as $item){
            echo $item['id'].PHP_EOL;
            $model=new UserRebate();
            $model->uid=$item['bind_uid'];
            $model->type=UserRebate::TYPE_GET;
            $model->order_id=$item['id'];
            $model->money=$item['rebate_price'];
            $model->date_ym=date("Ym",strtotime($item['pay_time']));
            $model->date_ymd=date("Ymd",strtotime($item['pay_time']));
            $model->status=UserRebate::STATUS_PASS;
            if(!$model->save())throw new \Exception(current($model->getFirstError()));
        }
    }

    public function actionErr(){
        $params=Yii::$app->request->get();
        if(!Cm::$redis->exists('is_err')){
            if(empty($params['is_err'])){
                echo '输入is_err提示';die;
            }
            Cm::$redis->set('is_err',$params['is_err']);
        }else{
            Cm::$redis->del('is_err');
        }
        echo Cm::$redis->get('is_err');
    }
}